<template>
    <div id="app">
        <div class="title">
            客服{{ curCustomerData.name }}({{ curCustomerData.status? '在线': '离线' }})
        </div>
        <div class="message-list" ref="wrapbox">
            <div class="message clearfix" v-for="(data, idx) of messageList" :key="idx">
                <!-- 系统消息 -->
                <div class="sys-msg" v-if="!data.userName" v-html="data.msg"></div>
                <!-- 名字+时间 -->
                <div class="user-id" :class="{'self': data.userName == curUser.username}" v-if="data.userName">
                    {{ data.userName == curUser.username? '': data.userName + '：' }}<em>{{ data.time }}</em></div>
                <!-- 文字消息 -->
                <div class="msg" :class="{'self': data.userName == curUser.username}" v-if="data.userName && data.msg" v-html="dealImg(data.msg)"></div>
                <!-- 图片 -->
                <div class="msg" :class="{'self': data.userName == curUser.username}" v-if="data.pic"><img class="img" :src="data.pic" @click="showBigImg(data.pic)"></div>
            </div>
        </div>
        <div class="msg-send">
            <form @submit.prevent="C2SMessage">
                <textarea placeholder="输入消息开始聊天吧 " @keypress.enter.prevent="C2SMessage" v-model="message" cols="30" rows="5"></textarea>
                <button>发送</button>
            </form>
            <div class="emjoy">
                <span class="emjoy-icon" @click="imgShow = !imgShow"><i></i></span>
                <div class="emjoy-wrap" v-show="imgShow">
                    <ul>
                        <li v-for="(item, index) in imgsData" :key="index" @click="sendImg(item)"><img :src="item.src" :title="item.title"></li>
                    </ul>
                </div>
            </div>
            <div class="pic">
                <a href="javascript:;">
                    <span>发图</span>
                    <input type="file" id="files" multiple @change="upImgs($event)" :accept="filetypes">
                </a>
            </div>
            <span class="audio-btn" @click="audioStatus = !audioStatus">
                <span v-if="audioStatus">关闭</span>
                <span v-else>开启</span>
                提示音
            </span>
        </div>
        <div class="form-box" v-if="!hasUserName">
            <p style="margin-top: 120px;">请先登录</p>
            <div class="loadEffect">
                <span></span>
                <span></span>
                <span></span>
                <span></span>
                <span></span>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </div>
        <div class="img-mask" v-show="showImgMask" @click="showImgMask=false">
            <span>X</span>
            <img :src="showImgSrc" @click.prevent.stop>
        </div>
        <audio ref="audio">
            <source :src="tipvodio">
        </audio>  
    </div>
</template>
<script>
import { createSocket, destroySocket } from '@/socket'
import { IMGDAT } from '@/emjoy'

export default {
    name: 'app',
    data() {
        return {
            tipvodio: './call.mp3',
            audioStatus: true,
            messageList: [],
            curUser: {},
            message: '',
            hasUserName: false,
            imgsData: [],
            imgShow: false,
            filetypes: 'image/jpg,image/jpeg,image/png,image/gif',
            isLoading: false,
            picSrc: '',
            showImgSrc: '',
            showImgMask: false,
            customerList: [],
            curCustomerData: {
                status: false,
                name: '',
                fd: 0
            },

            // 心跳检测
            heartTimeout: 300 * 1000,
            heartTimer: null,
            heartServerTimer: null,
            // 用户检测
            closeTimer: null,
            userHeartTimer: null,
            // 用户状态保持时间 6h
            userHeartTime: 6 * 60 * 60 * 1000,
        }
    },

    created() {
        this.imgsData = IMGDAT.imgs
    },

    mounted() {
        window.addEventListener('message',  (e) => {
            try {
              // eslint-disable-next-line no-irregular-whitespace
        　　　　if (typeof(e.data) ==='string' ) {
                    if(e.data === 'close') {
                        this.closeSocket();
                    } else {
                        if(e.data === 'kf_show') {
                            // 已经连接，用户收起后展开
                            this.$nextTick(() => {
                              this.$refs.wrapbox.scrollTop = this.$refs.wrapbox.scrollHeight;
                            });
                        } else {
                            // 第一次连接
                            this.curUser = JSON.parse(e.data);
                            this.setName();
                        }
                    }
                }

            } catch (err) {
                console.log(err)
            }

        });
    },

    beforeDestroy() {
        this.closeSocket();   
    },

    watch: {
        messageList() {
            this.$nextTick(() => {
                this.$refs.wrapbox.scrollTop = this.$refs.wrapbox.scrollHeight;
            });
        }
    },

    methods: {
        // 重置心跳
        resetHeart() {
            this.heartTimer && clearTimeout(this.heartTimer);
            this.heartServerTimer && clearTimeout(this.heartServerTimer);
        },

        // 开始心跳检测
        startHeart() {
            this.resetHeart();

            this.heartTimer = setTimeout(()=> {
                // 发送心跳到后台
                this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                    msg: 'heartBeat',
                    site: this.curUser.site
                })

                this.heartServerTimer = setTimeout(()=> { 
                    // 后端没有返回关闭
                    this.closeSocket();
                }, 5000)

            }, this.heartTimeout)
        },

        // 用户心跳检测
        startUserHeart() {
            this.userHeartTimer && clearTimeout(this.userHeartTimer);
            this.closeTimer && clearTimeout(this.closeTimer);

            this.userHeartTimer = setTimeout(()=> {
                this.messageList.push({
                    time: this.getCurTime(),
                    msg: '检测您不在当前窗口活动，聊天将5s后自动关闭'
                })

                this.closeTimer = setTimeout(()=> {
                    this.closeSocket();
                    window.parent.postMessage('close', '*');
                }, 5000)

            }, this.userHeartTime)
        },

        closeSocket() {
            if(this.$socket) {
                this.customerList.length && this.customerList.forEach(v=> {
                    this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                        msg: '已离开',
                        accept_fd: v.data.fd,
                        site: this.curUser.site
                    })
                })

                // 关闭后重置客服信息
                this.curCustomerData.status = false;
                this.curCustomerData.name = '';
                this.curCustomerData.fd = 0;
                
                // this.timerIndex && clearInterval(this.timerIndex)
                this.$socket.removeListener(this.$socket.S2C_MESSAGE)
                destroySocket()
                // 关闭心跳检测
                this.resetHeart();
                this.userHeartTimer && clearTimeout(this.userHeartTimer);
            } 
        },

        getCurTime() {
            let curDate = new Date();
            let Y = curDate.getFullYear(),
                M = this._checktime(curDate.getMonth() + 1),
                D = this._checktime(curDate.getDate()),
                h = this._checktime(curDate.getHours()),
                m = this._checktime(curDate.getMinutes()),
                s = this._checktime(curDate.getSeconds());

            return `${Y}/${M}/${D} ${h}:${m}:${s}`
        },

        sendImg(item) {
            this.imgShow = false;
            this.message += `:)${ item.title }:`;
        },

        setName() {
            this.hasUserName = false;
            if(!this.curUser.username || this.curUser.username === '游客') return;
            // 开启连接
            createSocket();
            // 开启用户检测
            this.startUserHeart();

            this.$socket.addListener(this.$socket.S2C_MESSAGE, (...args) => {
                this.S2CMessage(...args)
            });

            this.hasUserName = true;

            this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                customer: 0,
                userID: this.curUser.userID || -1,
                headimg: this.curUser.headimg || '',
                username: this.curUser.username,
                site: this.curUser.site
            })
        },

        dealImg: function(data) {
            return data.replace(/&lt;img src="/g, '<img src="')
                .replace(/\.gif"&gt;/g, '.gif">')
        },

        // 收到服务器消息
        S2CMessage(data) {
            let newMsg = data.msg;
            if(data.customer === 1 || data.customer_info && data.customer_info.length) {
                // 有客服在线
                let customer_info;

                if(data.customer) {
                    this.customerList.push({data});
                    customer_info = data;
                } else {
                    this.customerList = [...data.customer_info];
                    // 随机分配客服
                    let index = Math.floor(Math.random(0,1) * this.customerList.length);

                    customer_info = this.customerList[index].data;
                }

                if(this.curCustomerData.fd === 0) {
                    this.curCustomerData.status = true;
                    this.curCustomerData.fd = customer_info.fd;
                    this.curCustomerData.name = customer_info.username;
                    if(this.curUser.qq.length > 15) {
                        newMsg = this.curUser.qq;
                    } else {
                        newMsg = '客服'+ this.curCustomerData.name +'很高兴为您服务' + (this.curUser.qq? ('，客服QQ：' + this.curUser.qq): '');
                    }
                } else {
                    data.msg = 'add'
                }
            } else {
                // 没有客服在线
                if(this.messageList.length && this.messageList[0].msg.indexOf('客服工作时间') > -1) {
                    !this.curCustomerData.status && this.messageList.push({
                        msg: this.getCurTime() +'<br> 当前暂无客服在线，请稍后再试'
                    })
                } else {
                    !this.curCustomerData.status && this.messageList.push({
                        msg: '客服工作时间<br> 周一至周五： 10:00 - 19:00<br><br> '+ this.getCurTime() +' 当前暂无客服在线，请稍后再试' + (this.curUser.qq? '<br>客服QQ：' + this.curUser.qq: '')
                    })
                }
            }

            if(data.msg === '已离开' || (data.customer_info && data.customer_info.length === 0)) {
                // 删除客服数组中离开客服
                let leaveKfName = '';
                this.customerList.forEach((v, i)=> {
                    if(v.data.fd === data.fd) {
                        leaveKfName = v.data.username;
                        this.customerList.splice(i, 1);
                    }
                })

                // 离开的是当前客服
                if(data.fd === this.curCustomerData.fd) {
                    // 查询其他在线客服
                    if(this.customerList.length) {
                        // 有客服，随机分配
                        let index = Math.floor(Math.random(0,1)*this.customerList.length);
                        let data = this.customerList[index].data;

                        this.curCustomerData = {
                            status: true,
                            fd: data.fd,
                            name: data.username
                        }

                        if(leaveKfName === data.username) {
                            newMsg = 'reconnect';
                        } else {
                            newMsg = `客服${leaveKfName}离开，客服${data.username}为您服务`;
                        }
                    } else {
                        // 没有在线客服修改客服状态
                        this.curCustomerData = {
                            status: false,
                            fd: 0,
                            name: ''
                        }

                        this.messageList.push({
                            userName: `客服`,
                            time: this.getCurTime(),
                            msg: '我暂时不在线，请稍后联系'
                        })
                    }


                } else {
                    // 离开其他用户客服不做提示
                    return;
                }
            }

            if(this.curCustomerData.status && data.msg !== 'heartbeat' && data.msg !== 'add' && newMsg !== 'reconnect') {
                !(newMsg.indexOf('很高兴为您服务') > -1) && this.audioStatus && this.$refs.audio.play();
                window.parent.postMessage('msgs', '*');

                // 客服发消息过来，指定他为当前客服
                data.fd && (this.curCustomerData.fd = data.fd);

                if(newMsg.indexOf('很高兴为您服务') > -1) {
                    if(this.messageList.length) return;
                }

                this.messageList.push({
                    userName: `客服${this.curCustomerData.name}`,
                    time: data.time_show || this.getCurTime(),
                    msg: newMsg,
                    pic: data.pic
                })
            }

            // 心跳检测
            this.startHeart();
        },

        // 发送到服务器
        C2SMessage() {
            if(!this.curCustomerData.status) {
                alert('客服不在线，请稍后再试')
                return;
            }
            if (!this.message.trim() && !this.picSrc) return;

            this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                msg: this._htmlfilter(this.message),
                pic: this.picSrc,
                userID: this.curUser.userID || -1,
                accept_fd: this.curCustomerData.fd,
                site: this.curUser.site
            })

            this.messageList.push({
                msg: this._htmlfilter(this.message),
                userName: this.curUser.username,
                pic: this.picSrc,
                time: this.getCurTime(),
            })

            this.message = ''
            this.picSrc = ''

            // 重置用户心跳
            this.startUserHeart();
        },

        returnImg(str) {
            let src;
            this.imgsData.forEach(v=> {
                if(v.title == str) {
                    src = v.src
                }
            })
            return `<img src="${ src }">`;
        },

        _htmlfilter(str) {
            let _this = this;
            if(typeof str != 'string') {
                return str;
            }
            let imgreg = /:\)\S{2}:/g;
            let reg = /[<>]/gi;
            return str
            .replace(imgreg, function(data) {
                let newStr = _this.returnImg(data.match(/[^:)]{2}/)[0])
                return newStr
            }).replace(reg, function(match) {
                switch(match) {
                    case '<':
                        return '&lt;'
                    case '>':
                        return '&gt;'
                    default:
                        break;
                }
            })
        },

        _checktime(i) {
            if(i < 10) {  
                i = "0" + i;  
            }  
            else{ i = i;}  
            return i;  
        },

        upImgs: function(event) {
            var fil = event.target.files;
            for (var i = 0; i < fil.length; i++) {
                this._reads(fil[i]);
            }
        },

        _reads: function(fil) {
            if(fil.type.indexOf('image') == -1) {
                alert('仅能上传图片类型')
                return;
            }
            var reader = new FileReader(),
                _this = this;
            reader.readAsDataURL(fil);
            reader.onloadstart = function () {  
                _this.isLoading = true;
            }
            reader.onload = function(){
                _this.isLoading = false;
                var image = new Image();
                image.src = reader.result;
                if(fil.size >= 1024*1024*2 ) {
                    alert('图片过大！');
                    return;
                }
                image.onload=function(){
                    _this.picSrc = reader.result;
                    _this.C2SMessage();
                };
            };
        },

        showBigImg(src) {
            this.showImgMask = true;
            this.showImgSrc = src;
        },

        // msgTipsShow() {
        //     let _this = this;
        //     let title = _this.msgTitle.replace("【　　　】", "").replace("【新消息】", "");
        //     _this.msgTimer = setTimeout(function () {  
        //         _this.msgTime++;  
        //         clearTimeout(_this.msgTimer);
        //         _this.msgTipsShow();
        //         if (_this.msgTime % 2 == 0) {  
        //             document.title = "【新消息】" + title  
        //         } else {  
        //             document.title = "【　　　】" + title  
        //         };  
        //     }, 500);  
        // },

        // clearMsgTip() {
        //     clearTimeout(this.msgTimer);  
        //     this.msgTime = 0;
        //     document.title = this.msgTitle;
        // }
    }
}
</script>
<style>
body {
    background: #FAFBFC
}

#app {
    font-family: 'Avenir', Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #fff;
    width: 50rem;
    max-width: 100%;
    background: #333;
    position: fixed;
    transform: translate(-50%, 0);
    left: 50%;
    display: flex;
    flex-direction: column;
    top: 0px;
    bottom: 0px;
    min-width: 360px;
}

.clearfix::before,
.clearfix::after {
   content: ""; 
    zoom: 1; 
    visibility: hidden; 
    display : block;
    clear : both;
}
    /*  */

.form-box {
    position: fixed;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    background-color: rgba(0,0,0,.8);
    z-index: 9999;
    text-align: center;
    /* display: none; */
}

.form-box form {
    width: 300px;
    height: 40px;
    background-color: #fff;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -20px;
    margin-left: -150px;
}

.form-box form * {
    outline: none;
    border: none;
    vertical-align: middle;
    height: 100%;
}

.form-box form input {
    width: 100%;
    padding: 0 55px 0 5px;
    box-sizing: border-box;
}

.form-box form button {
    position: absolute;
    height: 40px;
    right: 0;
    top: 0;
    width: 50px;
    cursor: pointer;
}

.title {
    flex-shrink: 0;
    padding: .5rem;
}

.message-list {
    flex: auto;
    background: white;
    overflow: auto;
    padding-bottom: 10px;
}

.message-list::-webkit-scrollbar-track {
    background-color: #fff;
}

.message-list::-webkit-scrollbar {
    width : 4px;
    background-color: #fff; 
}
            
.message-list::-webkit-scrollbar-thumb {
    background-color: #eee; 
}


.message-list .message {
    text-align: left;
    padding: .5rem 1rem;
}

.sys-msg {
    text-align: center;
    color: #999;
    font-size: 13px;
}

.sys-msg span {
    color: #00bfff;
}

.message-list .message .user-id {
    color: #00bfff;
    float: left;
    width: 100%;
    text-align: left;
}

.message-list .message .user-id em {
    color: #888;
    font-style: normal;
    font-size: 14px
}

.message-list .message .user-id.self {
    text-align: right;
    float: right;
}

.message-list .message .msg {
    margin: .5rem 1rem;
    padding: 8px;
    background: #c4e6ff;
    border-radius: 4px;
    float: left;
    max-width: 55%;
    color: #333;
}

.message-list .message .msg img {
    height: 30px;
    vertical-align: text-bottom;
}

.message-list .message .msg img.img {
    max-width: 100%;
    height: auto;
}

.message-list .message .msg.self {
    float: right;
}

.msg-send {
    flex-shrink: 0;
    display: flex;
    padding: 4px;
    position: relative;
}

.msg-send form {
    display: block;
    width: 100%;
}

.msg-send textarea {
    width: 100%;
    box-sizing: border-box;
    border-radius: 4px;
    resize: none;
    padding: 8px 10px;
    outline: none;
}

.msg-send button {
    float: right;
    margin: 4px 0;
    align-self: flex-end;
    border-radius: 4px;
    border: none;
    background: #57a3f3;
    color: white;
    height: 2rem;
    padding: 0 1.5rem;
    line-height: 2rem;
    cursor: pointer;
    outline: none;
}

.emjoy {
    position: absolute;
    bottom: 12px;
    right: 100px;
    height: 25px;
}

.emjoy-icon {
    display: block;
    height: 100%;
    width: 25px;
    border-radius: 50%;
    border: 1px solid #fff;
    position: relative;
    cursor: pointer;
}

.emjoy-icon i {
    width: 14px;
    height: 14px;
    border-right: 1px solid #fff;
    border-radius: 50%;
    position: absolute;
    bottom: 5px;
    left: 50%;
    margin-left: -7.5px;
    transform: rotate(90deg)
}

.emjoy-icon:before,
.emjoy-icon:after {
    content:  "";
    position: absolute;
    width: 4px;
    height: 4px;
    top: 8px;
    left: 6px;
    border-radius: 50%;
    background-color: #fff;
}

.emjoy-icon:after {
    left: 15px;
}

.emjoy .emjoy-wrap {
    position: absolute;
    bottom: 25px;
    right: 25px;
    border-radius: 5px;
    background-color: #fff;
    width: 384px;
    height: 200px;
    box-shadow: 0 0 10px 0 rgba(0,0,0,.1);
    font-size: 0;
    padding: 10px;
    text-align: left;
}

@media screen and (max-width: 800px)  {
    .emjoy .emjoy-wrap {
        right: 15px;
        bottom: 30px;
        width: 220px;
        height: 150px;
    }

    .emjoy .emjoy-wrap ul li img {
        width: 36px;
    }
}

.emjoy .emjoy-wrap ul {
    padding: 0;
}

.emjoy .emjoy-wrap ul li {
    display: inline-block;
    list-style: none;
    margin: 4px;
    cursor: pointer;
}

.img-mask {
    position: fixed;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    background-color: rgba(0,0,0,.8);
    z-index: 9999;
    text-align: center;
}

.img-mask span {
    position: absolute;
    right: 0px;
    top: 0px;
    font-size: 20px;
    color: #fff;
    width: 50px;
    height: 50px;
    cursor: pointer;
    text-align: center;
    line-height: 50px;
    z-index: 2;
    background-color: rgba(0,0,0,.4);
}

.img-mask img {
    max-width: 100%;
    max-height: 100%;
    position: absolute;
    margin: auto;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
}

.msg-send .pic {
    position: absolute;
    bottom: 10px;
    right: 150px;
    height: 25px;
    width: 100px;
    cursor: pointer;
}

.msg-send .pic input {
    opacity: 0;
    position: absolute;
    left: 0;
    width: 100px;
    cursor: pointer;
}

.msg-send .pic a {
    color: #fff;
    text-decoration: none;
    display: block;
    width: 100%;
    height: 100%;
}

.msg-send .audio-btn {
    position: absolute;
    left: 10px;
    bottom: 15px;
    font-size: 12px;
    color: #ddd;
    cursor: pointer;
}

.loadEffect {
    width:100px;
    height:100px;
    position:absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
.loadEffect span {
    display:inline-block;
    width:16px;
    height:16px;
    border-radius:50%;
    background:#48a5f4;
    position:absolute;
    -webkit-animation:load 1.04s ease infinite;
}
@-webkit-keyframes load {
    0% {
    opacity:1;
}
100% {
    opacity:0.2;
}
}.loadEffect span:nth-child(1) {
    left:0;
    top:50%;
    margin-top:-8px;
    -webkit-animation-delay:0.13s;
}
.loadEffect span:nth-child(2) {
    left:14px;
    top:14px;
    -webkit-animation-delay:0.26s;
}
.loadEffect span:nth-child(3) {
    left:50%;
    top:0;
    margin-left:-8px;
    -webkit-animation-delay:0.39s;
}
.loadEffect span:nth-child(4) {
    top:14px;
    right:14px;
    -webkit-animation-delay:0.52s;
}
.loadEffect span:nth-child(5) {
    right:0;
    top:50%;
    margin-top:-8px;
    -webkit-animation-delay:0.65s;
}
.loadEffect span:nth-child(6) {
    right:14px;
    bottom:14px;
    -webkit-animation-delay:0.78s;
}
.loadEffect span:nth-child(7) {
    bottom:0;
    left:50%;
    margin-left:-8px;
    -webkit-animation-delay:0.91s;
}
.loadEffect span:nth-child(8) {
    bottom:14px;
    left:14px;
    -webkit-animation-delay:1.04s;
}
</style>